#ifndef __MY_UTIL__
#define __MY_UTIL__
#include<iostream>
#include<fstream>
#include<string>
#include<vector>
#include<sys/stat.h>
#include<experimental/filesystem>
#include"bundle.h"
#include<stdio.h>
#include<jsoncpp/json/json.h>
namespace cloud{
	namespace fs=std::experimental::filesystem;
	class FileUtil{		
		private:
			std::string _filename;
		public:
			FileUtil(const std::string &filename):_filename(filename){}
			int64_t FileSize()
			{
				struct stat st;
				if(stat(_filename.c_str(),&st)<0)
				{
					std::cout<<"get file size failed!\n";
					return -1;
				}
				return st.st_size;

			}
			time_t LastMTime(){
				struct stat st;
				if(stat(_filename.c_str(),&st)<0)
				{
					std::cout<<"get file last mtimg failed!\n";
					return -1;
				}
				return st.st_mtime;
			}
	
			time_t LastATime(){
				struct stat st;
				if(stat(_filename.c_str(),&st)<0)
				{
					std::cout<<"get file last atimg failed!\n";
					return -1;
				}
				return st.st_atime;
			}
			std::string FileName()
			{
				size_t pos;
				pos=_filename.find_last_of("/");
				if(pos==std::string::npos)
				{
					std::cout<<"find name failed!\n";
					exit;
				}
				return _filename.substr(pos+1);
			}

			bool GetPosLen(std::string &body,size_t pos,size_t len)
			{
				if(this->FileSize()<pos+len)
				{
					std::cout<<"GetPosLen failed!\n";
					return false;
				}
				std::ifstream ifs;
				ifs.open(_filename,std::ios::binary);
				if(ifs.good()==false)
				{
					std::cout<<"open file failed!\n";
					return false;
				}
				ifs.seekg(pos,std::ios::beg);
				body.resize(len);
				ifs.read(&body[0],len);
				if(!ifs.good())
				{
					std::cout<<"read failede!\n";
					return false;
				}
				ifs.close();
				return true;
			}
			bool GetContent(std::string *body)
			{ 
				size_t fsize=this->FileSize();
				return GetPosLen(*body,0,fsize);
			}

			bool SetContent(const std::string &body)
			{
				std::ofstream ofs;
				ofs.open(_filename,std::ios::binary);
				if(ofs.is_open()==false)
				{
					std::cout<<"write open failede!\n";
					return false;
				}
				ofs.write(&body[0],body.size());
				if(!ofs.good())
				{
					std::cout<<"write failede!\n";
					return false;
				}
				ofs.close();
				return true;
			}

			bool Compress(const std::string &packname)
			{
				std::string body;
				this->GetContent(&body);
				std::string packed=bundle::pack(bundle::LZIP,body);
				FileUtil fu(packname);
				if(fu.SetContent(packed)==false)
				{
					std::cout<<"compress failed!\n";
					return false;	
				}
				return true;
			}
			bool UnCompress(const std::string packname)
			{	
				std::string body;
				this->GetContent(&body);
				std::string upbody2;
				upbody2=bundle::unpack(body);
				FileUtil fu(packname);
				if(fu.SetContent(upbody2)==false)
				{
					std::cout<<"uncompress failed!\n";
					return false;
				}
				return true;			
			}
			bool Remove(){
				if(this->Exists()==false)
					return true;
				remove(_filename.c_str());
				return true;
			}
			bool Exists()
			{
				return fs::exists(_filename);
			}
			bool CreateDirectory()
			{	
				if(this->Exists()==true)
				{
					return true;	
				}		
				return fs::create_directories(_filename);
			}
			bool ScanDirectory(std::vector<std::string>* arry )
			{	
				for(auto& p:fs::directory_iterator(_filename))
				{	
					if(fs::is_directory(p))
					continue;
					arry->push_back(fs::path(p).relative_path().string());
				}
				return true;
			}
};
	class JsonUtil{
		public:
			static bool Serialize(Json::Value &root,std::string *str)
			{
				Json::StreamWriterBuilder swb;
				std::unique_ptr<Json::StreamWriter> sw(swb.newStreamWriter());
				std::stringstream ss;
				sw->write(root,&ss);
				*str=ss.str();
				return true;
			}
			static bool UnSerialize(std::string &str,Json::Value *root)
			{
				Json::CharReaderBuilder crb;
				std::unique_ptr<Json::CharReader> cr(crb.newCharReader());
				std::string err;
				bool ret=cr->parse(str.c_str(),str.c_str()+str.size(),root,&err);
				if(ret==false)
				{
					std::cout<<"error:"<<err<<std::endl;
					return false;
				}
				return true;
			}
};	
}
#endif
